import base64
import logging
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class AESUtils(object):
    """
    AES加密工具类 (Python实现)
    功能：提供AES-128-CBC模式的加密解密功能，使用固定IV和密钥
    限制：密钥必须为16位，使用PKCS5Padding填充方式
    """

    AES = "AES"
    TRANSFORMATION = "AES/CBC/PKCS5Padding"
    IV = "fa4567ce012389ai"
    KEY = "dvyYRQlnPRCMdQSe"
    KEY_LENGTH = 16
    CHARSET = 'utf-8'

    @staticmethod
    def aes_encode(encode_rules: str, content: str) -> str:
        """
        AES加密方法
        :param encode_rules: 加密规则(作为密钥使用)
        :param content: 要加密的内容
        :return: 加密后的Base64字符串
        """
        logger.info(f"开始进行AES加密 encode_rules:{encode_rules},content:{content}")

        try:
            cipher = AESUtils._init_aes_cipher(encode_rules, AES.MODE_CBC)
            byte_encode = content.encode(AESUtils.CHARSET)
            byte_aes = cipher.encrypt(pad(byte_encode, AES.block_size))
            result = base64.b64encode(byte_aes).decode(AESUtils.CHARSET)
            logger.info(f"结束AES加密 encode_rules:{encode_rules},content:{content}，result：{result}")
            return result
        except Exception as e:
            logger.error(f"AES加密出错: {str(e)}", exc_info=True)
            return None

    @staticmethod
    def aes_decode(encode_rules: str, content: str) -> str:
        """
        AES解密方法
        :param encode_rules: 解密规则(作为密钥使用)
        :param content: 要解密的内容(Base64格式)
        :return: 解密后的原始字符串
        """
        logger.info(f"开始进行AES解密 encode_rules:{encode_rules},content:{content}")

        if not content:
            return ""

        try:
            cipher = AESUtils._init_aes_cipher(encode_rules, AES.MODE_CBC)
            byte_content = base64.b64decode(content.encode(AESUtils.CHARSET))
            byte_decode = unpad(cipher.decrypt(byte_content), AES.block_size)
            result = byte_decode.decode(AESUtils.CHARSET)
            logger.info(f"结束AES解密 encode_rules:{encode_rules},content:{content}，result：{result}")
            return result
        except Exception as e:
            logger.error(f"AES解密出错: {str(e)}", exc_info=True)
            return None

    @staticmethod
    def _init_aes_cipher(s_key: str, cipher_mode) -> AES:
        """
        初始化AES加密器
        :param s_key: 密钥字符串
        :param cipher_mode: 加密/解密模式
        :return: AES加密器实例
        """
        logger.info(f"init_aes_cipher start s_key:{s_key} cipher_mode:{cipher_mode}")

        if not s_key:
            raise ValueError("init_aes_cipher s_key is empty")

        # 使用SHA1PRNG算法模拟Java的密钥生成方式
        key = AESUtils._generate_key(s_key)
        iv = AESUtils.IV.encode(AESUtils.CHARSET)

        return AES.new(key, cipher_mode, iv=iv)

    @staticmethod
    def _generate_key(password: str) -> bytes:
        """
        模拟Java的SHA1PRNG密钥生成方式
        :param password: 密码字符串
        :return: 16字节的密钥
        """
        # 使用SHA1哈希模拟Java的SecureRandom(SHA1PRNG)
        digest = hashlib.sha1(password.encode(AESUtils.CHARSET)).digest()
        return digest[:AESUtils.KEY_LENGTH]

    @staticmethod
    def encrypt(s_src: str, s_key: str = 'YRQlnPRCdvyMdQSe') -> str:
        """
        便捷加密方法(使用默认密钥)
        :param s_src: 要加密的字符串
        :param s_key: 可选密钥(默认使用类变量KEY)
        :return: 加密后的Base64字符串
        """
        try:
            s_key = s_key or AESUtils.KEY
            return AESUtils._encrypt(s_src, s_key)
        except Exception as e:
            logger.error(f"加密出错: {str(e)}", exc_info=True)
            return ""

    @staticmethod
    def decrypt(s_src: str, s_key: str = 'YRQlnPRCdvyMdQSe') -> str:
        """
        便捷解密方法(使用默认密钥)
        :param s_src: 要解密的Base64字符串
        :param s_key: 可选密钥(默认使用类变量KEY)
        :return: 解密后的原始字符串
        """
        try:
            s_key = s_key or AESUtils.KEY
            return AESUtils._decrypt(s_src, s_key)
        except Exception as e:
            logger.error(f"解密出错: {str(e)}", exc_info=True)
            return ""

    @staticmethod
    def _encrypt(s_src: str, s_key: str) -> str:
        """
        核心加密实现
        :param s_src: 要加密的字符串
        :param s_key: 密钥(必须16位)
        :return: 加密后的Base64字符串
        """
        if not s_key:
            print("Key为空null")
            return None

        if len(s_key) != AESUtils.KEY_LENGTH:
            print("Key长度不是16位")
            return None

        key = s_key.encode(AESUtils.CHARSET)
        iv = AESUtils.IV.encode(AESUtils.CHARSET)
        cipher = AES.new(key, AES.MODE_CBC, iv=iv)
        padded_data = pad(s_src.encode(AESUtils.CHARSET), AES.block_size)
        encrypted = cipher.encrypt(padded_data)
        return base64.b64encode(encrypted).decode(AESUtils.CHARSET)

    @staticmethod
    def _decrypt(s_src: str, s_key: str) -> str:
        """
        核心解密实现
        :param s_src: 要解密的Base64字符串
        :param s_key: 密钥(必须16位)
        :return: 解密后的原始字符串
        """
        if not s_key:
            print("Key为空null")
            return None

        if len(s_key) != AESUtils.KEY_LENGTH:
            print("Key长度不是16位")
            return None

        key = s_key.encode(AESUtils.CHARSET)
        iv = AESUtils.IV.encode(AESUtils.CHARSET)
        cipher = AES.new(key, AES.MODE_CBC, iv=iv)
        encrypted_data = base64.b64decode(s_src.encode(AESUtils.CHARSET))
        decrypted = unpad(cipher.decrypt(encrypted_data), AES.block_size)
        return decrypted.decode(AESUtils.CHARSET)


if __name__ == "__main__":
    # 测试示例
    try:
        # 测试解密功能(与Java版本兼容)
        print(AESUtils.decrypt("PyFnxgj44+PP9cvMbaBHIg==", "YRQlnPRCdvyMdQSe"))

        # 测试加密解密流程
        original = "Hello, 世界!"
        encrypted = AESUtils.encrypt(original)
        print(f"加密结果: {encrypted}")
        decrypted = AESUtils.decrypt(encrypted)
        print(f"解密结果: {decrypted}")
    except Exception as e:
        print(f"测试出错: {str(e)}")
